/**
 * Widget Meteo : Projet Android 
 * @author Floriance BRIN, Julie ESCOFFIER, Yoann GOBERT, Ikram NACIRI, Yann NIVET
 * @version 1.0
 * @date mars 2011
 * **/

package fr.imac.ProjetAndroid.weatherGestion;

import java.io.InputStream;
import java.net.URL;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
/**
 * Classe pour lire les données météo à partir d'un flux xml
 */
public class WeatherReader {
	private String params;
	/**
	 * Nombre de jours de prévision stockés
	 */
	private static int numberOfPrevisionsDay = 5;
	/**
	 * Le tableau des prévisions ( sur 5 jours )
	 */
	private WeatherConditions[] arrayConditions = new WeatherConditions[numberOfPrevisionsDay];
	/**
	 * Les conditions actuelles
	 */
	private WeatherConditions currentConditions = null;
	/**
	 * notre ville étudiée
	 */
	private String city = "";
	private int code = 0;
	private Boolean isZipCode = false;
	
	/**
	 * Constructeur qui récupère les données météo à partir du code de la ville
	 * @param code : le code de la ville (zip ou cityCode)
	 * @param isZipcode : savoir si c'est un zipCode(true) ou un cityCode(false)
	 */
	public WeatherReader(int code, boolean isZipcode){
		initArrayConditions();
		//initialisation de l'adresse
		if(isZipcode){
			this.params = "&zipcode="+Integer.toString(code);
		}else{
			this.params = "&citycode="+Integer.toString(code);
		}
		//chargement des données de l'API
		//this.updateAll();		
	}
	/**
	 * Constructeur qui récupère les données météo à partir du code de la ville
	 * @param code : le code de la ville (zip ou cityCode)
	 * @param isZipcode : savoir si c'est un zipCode(true) ou un cityCode(false)
	 */
	public WeatherReader(String code, boolean isZipcode){
		initArrayConditions();
		//initialisation de l'adresse
		if(isZipcode){
			this.params = "&zipcode="+code;
		}else{
			this.params = "&citycode="+code;
		}
		//chargement des données de l'API
		//this.updateAll();		
	}
	/**
	 * Constructeur qui récupère les données météo à partir des coordonnées GPS
	 * @param lat : la latitude
	 * @param lon : la longitude
	 */
	public WeatherReader(double lat, double lon){
		initArrayConditions();
		//initialisation de l'adresse
		this.params = "&lat="+Double.toString(lat)+"&long="+Double.toString(lon);
		//chargement des données de l'API
		//this.updateAll();
	}
	/**
	 * Fonction qui initialise les conditions
	 */
	private void initArrayConditions(){
		for(int i=0; i<numberOfPrevisionsDay; i++){
			this.arrayConditions[i] = new WeatherConditions("0", "0", "0");
		}
	}
	/**
	 * fonction pour parser un flux xml à partir d'un flux la météo des jours à venir
	 * @param params : les paramètres à passer dans l'adresse
	 */
	private void loadAllWeather() throws Exception{
		String url = WeatherApiUrls.urlAllWeather+WeatherApiUrls.apiKey+this.params+WeatherApiUrls.urlLastParameters;
		URL myURL = new URL(url);
		
		SAXParserFactory spf = SAXParserFactory.newInstance();
		SAXParser sp = spf.newSAXParser();
		XMLReader xr = sp.getXMLReader();
		
		/** Create handler to handle XML Tags ( extends DefaultHandler ) */
		WeatherParserPrevisions myXMLHandler = new WeatherParserPrevisions();
		xr.setContentHandler(myXMLHandler);
		InputStream myStream =  myURL.openStream();
		xr.parse(new InputSource(myStream));
		
		//on ne prend que les conditions sur 5 jours
		for(int i=0; i<numberOfPrevisionsDay; i++){
			this.arrayConditions[i] = new WeatherConditions(
												myXMLHandler.getMinimalesAt(i),
												myXMLHandler.getMaximalesAt(i),
												myXMLHandler.getIllustrationsAt(i));						
		}
	}
	/**
	 * fonction pour parser un flux xml à partir d'un flux la météo actuelle
	 * @param params : les paramètres à passer dans l'adresse
	 */
	private void loadCurrentWeather(boolean updateCity) throws Exception{			
		String url = WeatherApiUrls.urlCurrentWeather+WeatherApiUrls.apiKey+this.params+WeatherApiUrls.urlLastParameters;
		URL myURL = new URL(url);
		
		SAXParserFactory spf = SAXParserFactory.newInstance();
		SAXParser sp = spf.newSAXParser();
		XMLReader xr = sp.getXMLReader();
		
		/** Create handler to handle XML Tags ( extends DefaultHandler ) */
		WeatherParserCurrent myXMLHandler = new WeatherParserCurrent();
		xr.setContentHandler(myXMLHandler);
		
		InputStream myStream =  myURL.openStream();
		xr.parse(new InputSource(myStream));
		if(updateCity){
			this.city = myXMLHandler.getCity();
			this.code = myXMLHandler.getCode();
			this.isZipCode = myXMLHandler.getIsZipCode();
		}
		
		//on recupere les conditions actuelles :
		this.currentConditions = new WeatherConditions(myXMLHandler.getCity(), myXMLHandler.getCurrentTemperature(), myXMLHandler.getIllustration());	
	}
	
	/**
	 * fonction qui retourne les conditions actuelles
	 * @return WeatherConditions : les conditions météo actuelles
	 */
	public WeatherConditions getCurrentWeatherCondition(){
		return this.currentConditions;
	}
	/**
	 * Fonction qui retourne toutes les conditions météo
	 * @return WeatherConditions[] : les conditions météo prévues
	 */
	public WeatherConditions[] getAllWeatherPrevisions(){
		return this.arrayConditions;
	}
	
	/**
	 * Recharge toutes les données météo
	 * @throws Exception
	 */
	public void updateAll() throws Exception{
		updateAll(true);
	}
	/**
	 * Recharge toutes les données météo
	 * @param updateCity : update le nom de la ville
	 * @throws Exception
	 */
	public void updateAll(boolean updateCity) throws Exception{
		this.loadCurrentWeather(updateCity);
		this.loadAllWeather();
	}
	/**
	 * Recharge les données météo actuelles
	 * @throws Exception
	 */
	public void updateCurrentWeather() throws Exception{
		updateCurrentWeather(true);
	}
	/**
	 * Recharge les données météo actuelles
	 * @param updateCity : update le nom de la ville
	 * @throws Exception
	 */
	public void updateCurrentWeather(boolean updateCity) throws Exception{
		this.loadCurrentWeather(updateCity);
	}
	/**
	 * @param city the city to set
	 */
	public void setCity(String city) {
		this.city = city;
	}
	/**
	 * @return the city
	 */
	public String getCity() {
		return city;
	}
	/**
	 * @param code the code to set
	 */
	public void setCode(int code) {
		this.code = code;
	}
	/**
	 * @return the code
	 */
	public int getCode() {
		return code;
	}
	/**
	 * @param isZipCode the isZipCode to set
	 */
	public void setIsZipCode(Boolean isZipCode) {
		this.isZipCode = isZipCode;
	}
	/**
	 * @return the isZipCode
	 */
	public Boolean getIsZipCode() {
		return isZipCode;
	}
	
}
